package com.lightsaber.trade.as.service.programme;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.lightsaber.trade.as.dao.programme.ProgrammeDao;
import com.lightsaber.trade.as.dao.programme.ProgrammePlanProjectionTypeDao;
import com.lightsaber.trade.as.dao.programme.SubjectGroupDao;
import com.lightsaber.trade.as.dao.programme.SubjectGroupItemDao;
import com.lightsaber.trade.as.entity.programme.BaseProgramme;
import com.lightsaber.trade.as.entity.programme.DurationType;
import com.lightsaber.trade.as.entity.programme.Programme;
import com.lightsaber.trade.as.entity.programme.ProgrammePlanProjectionType;
import com.lightsaber.trade.as.entity.programme.SubjectGroup;
import com.lightsaber.trade.as.entity.programme.SubjectGroupItem;
import com.lightsaber.trade.core.dao.BaseDao;
import com.lightsaber.trade.core.service.BaseServiceImpl;

/**
 * @author LiuJian
 * 
 */
@Service
@Transactional
public class ProgrammePlanProjectionTypeManager extends
        BaseServiceImpl<ProgrammePlanProjectionType, String> {

    @Autowired
    private ProgrammePlanProjectionTypeDao programmePlanProjectionTypeDao;
    @Autowired
    private SubjectGroupItemDao subjectItemGroupDao;
    @Autowired
    private SubjectGroupDao subjectGroupDao;
    @Autowired
    private ProgrammeDao programmeDao;

    @Override
    protected BaseDao<ProgrammePlanProjectionType, String> getDao() {
        return programmePlanProjectionTypeDao;
    }

    /**
     * When save one new Programme, save Programme Plan Projection Type
     * 
     * @author LiuJian
     * 
     * @param dbProgramme
     *            online status in hibernate session
     * @param isNewProgramme
     * @param newDuration
     */
    public void onSaveNewProgramme(final BaseProgramme persistentProgramme) {

        // 1. Save projecttype
        Integer duration = 1;
        if (persistentProgramme.getDurationType() == DurationType.Year) {
            duration = persistentProgramme.getDuration();
        }

        for (Integer year = 1; year < duration; year++) {
            ProgrammePlanProjectionType pt = new ProgrammePlanProjectionType();
            pt.setProgramme(persistentProgramme);
            pt.setYear(year);
            this.save(pt);
        }

    }

    public void changeFeederOnNewProgramme(final Programme persistentProgramme) {

        // 1. if it is a feeder
        SubjectGroup subjectGroup = subjectGroupDao.findByCodeAndPlanYear(
                persistentProgramme.getCode(), persistentProgramme.getLaunchYear());

        if (subjectGroup != null) {
            programmePlanProjectionTypeDao.deleteOwedByFeeder(persistentProgramme);

            List<Programme> receivers = programmeDao.findReceivers(subjectGroup);
            for (Programme receiver : receivers) {
                programmePlanProjectionTypeDao.deleteFirstYearFromReceiver(receiver);

                ProgrammePlanProjectionType pt = programmePlanProjectionTypeDao
                        .findByProgrammeAndSubjectGroupPorgramme(persistentProgramme, receiver);

                if (pt == null) {

                    pt = new ProgrammePlanProjectionType();
                    pt.setProgramme(persistentProgramme);
                    pt.setSubjectGroupPorgramme(receiver);
                    pt.setYear(1);
                    super.save(pt);
                }
            }

            return;
        }

        // 2. if it is a receiver
        List<SubjectGroupItem> items = subjectItemGroupDao
                .findByCode(persistentProgramme.getCode());
        if (items != null && items.size() > 0) {
            programmePlanProjectionTypeDao.deleteFirstYearFromReceiver(persistentProgramme);

            for (SubjectGroupItem item : items) {
                SubjectGroup group = item.getSubjectGroup();

                List<Programme> feeders = programmeDao.findFeeders(group);

                for (Programme feeder : feeders) {
                    programmePlanProjectionTypeDao.deleteOwedByFeeder(feeder);

                    ProgrammePlanProjectionType pt = programmePlanProjectionTypeDao
                            .findByProgrammeAndSubjectGroupPorgramme(feeder, persistentProgramme);

                    if (pt == null) {
                        pt = new ProgrammePlanProjectionType();
                        pt.setProgramme(feeder);
                        pt.setSubjectGroupPorgramme(persistentProgramme);
                        pt.setYear(1);
                        super.save(pt);
                    }
                }
            }
        }

    }

    public void changeFeederOnDelProgramme(final Programme persistentProgramme) {
        List<SubjectGroupItem> items = subjectItemGroupDao
                .findByCode(persistentProgramme.getCode());

        if (items != null && items.size() > 0) {
            programmePlanProjectionTypeDao.deleteFirstYearFromReceiver(persistentProgramme);

            for (SubjectGroupItem item : items) {
                SubjectGroup group = item.getSubjectGroup();

                List<Programme> feeders = programmeDao.findFeeders(group);

                for (Programme feeder : feeders) {
                    ProgrammePlanProjectionType pt = programmePlanProjectionTypeDao
                            .findByProgrammeAndSubjectGroupPorgramme(feeder, persistentProgramme);

                    if (pt != null) {
                        super.delete(pt);
                    }
                }
            }
        }

    }

    public void changeFeederOnUpdateGroup(final SubjectGroup subjectGroup) {
        List<Programme> feeders = programmeDao.findFeeders(subjectGroup);

        List<Programme> receivers = programmeDao.findReceivers(subjectGroup);

        ProgrammePlanProjectionType pt = null;

        for (Programme feeder : feeders) {
            programmePlanProjectionTypeDao.deleteOwedByFeeder(feeder);

            for (Programme receiver : receivers) {
                programmePlanProjectionTypeDao.deleteFirstYearFromReceiver(receiver);

                pt = programmePlanProjectionTypeDao.findByProgrammeAndSubjectGroupPorgramme(feeder,
                        receiver);

                if (pt == null) {

                    pt = new ProgrammePlanProjectionType();
                    pt.setProgramme(feeder);
                    pt.setSubjectGroupPorgramme(receiver);
                    pt.setYear(1);
                    super.save(pt);
                }

            }
        }

    }

    public void changeFeederOnDeleteGroup(final SubjectGroup subjectGroup) {
        List<Programme> feeders = programmeDao.findFeeders(subjectGroup);

        List<Programme> receivers = programmeDao.findReceivers(subjectGroup);

        for (Programme feeder : feeders) {

            // 1. Heal the feeder: delete all "1-2", and add it's owned
            // projection type
            programmePlanProjectionTypeDao.deleteByProgramme(feeder);
            this.onSaveNewProgramme(feeder);

            for (Programme receiver : receivers) {

                // 2. Heal the receiver: add the first year projection type
                ProgrammePlanProjectionType pt = programmePlanProjectionTypeDao
                        .findByProgrammeAndYear(receiver, 1);

                if (pt == null) {
                    pt = new ProgrammePlanProjectionType();
                    pt.setProgramme(receiver);
                    pt.setYear(1);
                    super.save(pt);
                }

            }
        }

    }

    public void changeFeederOnDeleteGroupItem(final SubjectGroup subjectGroup,
            final SubjectGroupItem subjectGroupItem) {

        List<Programme> feeders = programmeDao.findFeeders(subjectGroup);

        List<Programme> receivers = programmeDao.findReceivers(subjectGroup, subjectGroupItem);

        for (Programme feeder : feeders) {

            for (Programme receiver : receivers) {
                // 1. Heal the feeder: delete the "1-2"
                programmePlanProjectionTypeDao.deleteByProgrammeAndSubjectGroupPorgramme(feeder,
                        receiver);

                // 2. Heal the receiver: add the first year projection type
                ProgrammePlanProjectionType pt = programmePlanProjectionTypeDao
                        .findByProgrammeAndYear(receiver, 1);

                if (pt == null) {
                    pt = new ProgrammePlanProjectionType();
                    pt.setProgramme(receiver);
                    pt.setYear(1);
                    super.save(pt);
                }
            }
        }

    }

    public List<ProgrammePlanProjectionType> findByProgramme(final BaseProgramme programme) {
        return programmePlanProjectionTypeDao.findByProgramme(programme);
    }

    public ProgrammePlanProjectionType findByProgrammeAndYearWithoutSub(
            final BaseProgramme programme, final int year) {
        return programmePlanProjectionTypeDao.findByProgrammeAndYearWithoutSub(programme, year);
    }

    public ProgrammePlanProjectionType findByProgrammeIdAndSubjectGroupIdAndYear(
            final String programmeId, final String subjectGroupId, final int year) {
        return programmePlanProjectionTypeDao.findByProgrammeIdAndSubjectGroupIdAndYear(
                programmeId, subjectGroupId, year);
    }

    public void batchSave(final List<ProgrammePlanProjectionType> projectionTypes) throws Exception {

        for (int i = 0; i < projectionTypes.size(); i++) {
            // for (ProgrammePlanProjectionType projectionType :
            // projectionTypes) {
            ProgrammePlanProjectionType projectionType = projectionTypes.get(i);
            ProgrammePlanProjectionType oldProjectionType = programmePlanProjectionTypeDao
                    .load(projectionType.getId());

            oldProjectionType.setPlanProjectionType(projectionType.getPlanProjectionType());
            oldProjectionType.setSelfDefinedProgressionRate(projectionType
                    .getSelfDefinedProgressionRate());

            programmePlanProjectionTypeDao.save(oldProjectionType);
        }
    }

}
